package com.probiz.estore.inventory.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import com.probiz.estore.common.helper.ConfigUtil;
import com.probiz.estore.common.model.inventory.Inventory;
import com.probiz.estore.common.model.inventory.InventoryAudit;
import com.probiz.estore.common.model.inventory.InventorySearchCriteria;
import com.probiz.estore.common.model.inventory.InventorySettingModel;
import com.probiz.estore.common.model.order.SalesOrder;
import com.probiz.estore.common.model.product.ProductSku;
import com.probiz.estore.common.model.system.AppUser;
import com.probiz.estore.core.search.SearchCriteria;
import com.probiz.estore.core.service.impl.GenericManagerImpl;
import com.probiz.estore.exception.OutOfStockException;
import com.probiz.estore.inventory.InventoryConstants;
import com.probiz.estore.inventory.dao.InventoryDao;
import com.probiz.estore.inventory.service.InventoryAuditManager;
import com.probiz.estore.inventory.service.InventoryManager;
import com.probiz.estore.product.dao.ProductSkuDao;
import com.probiz.estore.system.service.MsgSendManager;
import com.probiz.estore.system.util.MsgTemplateConstants;
import com.probiz.estore.webapp.util.RequestContext;


/**
 * Manager implementation for Inventory, responsible for business processing, and communicate between web and persistence layer.
 */
public class InventoryManagerImpl extends GenericManagerImpl<Inventory> implements InventoryManager {

	private InventoryDao inventoryDao = null;
	private ProductSkuDao productSkuDao = null;
	private InventoryAuditManager inventoryAuditManager = null;
	private ConfigUtil			configUtil			= ConfigUtil.getInstance();
	private MsgSendManager msgSendManager = null;
	
	
	public void setMsgSendManager(MsgSendManager msgSendManager) {
		this.msgSendManager = msgSendManager;
	}

	public void setInventoryDao(InventoryDao inventoryDao) {
		this.inventoryDao = inventoryDao;
	}

	public void setProductSkuDao(ProductSkuDao productSkuDao) {
		this.productSkuDao = productSkuDao;
	}
	
	public void setInventoryAuditManager(InventoryAuditManager inventoryAuditManager) {
		this.inventoryAuditManager = inventoryAuditManager;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.core.service.impl.GenericManagerImpl#init()
	 */
	@Override
	protected void initManager() {
		dao = inventoryDao;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.core.service.impl.GenericManagerImpl#preDelete(java.lang.Object)
	 */
	@Override
	protected void preDelete(Inventory entity) {

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.probiz.estore.core.service.impl.GenericManagerImpl#preSave(java.lang.Object)
	 */
	@Override
	protected void preSave(Inventory entity) {

	}
	
	/*
	 * (non-Javadoc)
	 * @see com.probiz.estore.inventory.service.InventoryManager#saveInventorysFromArrays(java.lang.String[], java.lang.String[])
	 */
	public void saveInventorysFromArrays(String[] productSkuIds,String[] inventorys){
		for(int i=0; i<productSkuIds.length; i++){
			ProductSku productSku = productSkuDao.getById(Integer.parseInt(productSkuIds[i]));
			Inventory inventory = productSku.getInventory();
			if(null == inventory){
				//新建库存
				inventory = new Inventory();
				if(StringUtils.isBlank(inventorys[i])){
					//无限库存
					inventory.setQuantityOnHand(null);
					inventory.setAllocatedQuantity(0);
					inventory.setReorderMinimnm(0);
				}else{
					inventory.setQuantityOnHand(Integer.parseInt(inventorys[i]));
					inventory.setAllocatedQuantity(0);
					inventory.setReorderMinimnm(0);
				}
				inventoryDao.save(inventory);
				productSku.setInventory(inventory);
				productSkuDao.save(productSku);
				//新建暂不需要有历史记录
			}else{
				//修改库存
				Integer quantityOnHand;
				if(StringUtils.isBlank(inventorys[i])){
					quantityOnHand = null;
				}else{
					quantityOnHand = Integer.parseInt(inventorys[i]);
				}
				doAdjustQuantityOnHand(productSku,quantityOnHand,"");
			}
			
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.probiz.estore.inventory.service.InventoryManager#doAdjustQuantityOnHand(com.probiz.estore.common.model.product.ProductSku, java.lang.Integer, java.lang.String)
	 */
	public Inventory doAdjustQuantityOnHand(ProductSku sku,Integer quantityOnHand,String comment){
		Inventory inventory = sku.getInventory();
		if( (inventory.getQuantityOnHand() == null && quantityOnHand==null)
		  || ((inventory.getQuantityOnHand() != null && quantityOnHand!=null && inventory.getQuantityOnHand().equals(quantityOnHand)))	
		)return inventory;//如果数量没改变则不需要变化   
		
		//-----------start:保存库存明细-------------
		InventoryAudit inventoryAudit=new InventoryAudit();
		inventoryAudit.setInventory(inventory);
		inventoryAudit.setProductSku(sku);
		inventoryAudit.setPreQuantityOnHand(inventory.getQuantityOnHand());
		inventoryAudit.setPostQuantityOnHand(quantityOnHand);
		inventoryAudit.setPreAllocatedQuantity(inventory.getAllocatedQuantity());
		inventoryAudit.setPostAllocatedQuantity(inventory.getAllocatedQuantity());
		if(inventoryAudit.getPreQuantityOnHand()!=null && inventoryAudit.getPostQuantityOnHand()!=null){
			inventoryAudit.setQuantity(inventoryAudit.getPostQuantityOnHand() - inventoryAudit.getPreQuantityOnHand());
		}
		inventoryAudit.setEventType(InventoryConstants.INVENTORY_AUDIT_EVENT_TYPE_STOCK_ADJUSTMENT);
		inventoryAudit.setComment(comment);
		inventoryAudit.setEventHandler(getHandler());
		inventoryAuditManager.save(inventoryAudit);
		//-----------end:  保存库存明细-------------
		
		//-----------start:保存库存-------------
		inventory.setQuantityOnHand(quantityOnHand);
		save(inventory);
		//-----------end:  保存库存-------------
		return inventory;
	}
	/*
	 * (non-Javadoc)
	 * @see com.probiz.estore.inventory.service.InventoryManager#doAddStock4OrderReturn(com.probiz.estore.common.model.order.SalesOrder, com.probiz.estore.common.model.product.ProductSku, java.lang.Integer)
	 */
	public Inventory doAddStock4OrderReturn(SalesOrder salesOrder,ProductSku sku,Integer quantity){
		Inventory inventory = sku.getInventory();
		if( quantity == null || quantity == 0)return inventory;   
		
		//-----------start:保存库存明细-------------
		Integer quantityOnHand = inventory.getQuantityOnHand();
		if(null != quantityOnHand){
			quantityOnHand += quantity;
		}
		InventoryAudit inventoryAudit=new InventoryAudit();
		inventoryAudit.setInventory(inventory);
		inventoryAudit.setSalesOrder(salesOrder);
		inventoryAudit.setProductSku(sku);
		inventoryAudit.setPreQuantityOnHand(inventory.getQuantityOnHand());
		inventoryAudit.setPostQuantityOnHand(quantityOnHand);
		inventoryAudit.setPreAllocatedQuantity(inventory.getAllocatedQuantity());
		inventoryAudit.setPostAllocatedQuantity(inventory.getAllocatedQuantity());
		if(inventoryAudit.getPreQuantityOnHand()!=null && inventoryAudit.getPostQuantityOnHand()!=null){
			inventoryAudit.setQuantity(inventoryAudit.getPostQuantityOnHand() - inventoryAudit.getPreQuantityOnHand());
		}
		inventoryAudit.setEventType(InventoryConstants.INVENTORY_AUDIT_EVENT_TYPE_STOCK_ADD_4_ORDER_RETURN);
		inventoryAudit.setEventHandler(getHandler());
		inventoryAuditManager.save(inventoryAudit);
		//-----------end:  保存库存明细-------------
		
		//-----------start:保存库存-------------
		inventory.setQuantityOnHand(quantityOnHand);
		save(inventory);
		//-----------end:  保存库存-------------
		return inventory;
	}
	/*
	 * (non-Javadoc)
	 * @see com.probiz.estore.inventory.service.InventoryManager#doAdjustReorderMinimnm(com.probiz.estore.common.model.product.ProductSku, java.lang.Integer, java.lang.String)
	 */
	public Inventory doAdjustReorderMinimnm(ProductSku sku,Integer reorderMinimnm,String comment){
		Inventory inventory = sku.getInventory();
		inventory.setReorderMinimnm(reorderMinimnm);
		save(inventory);
		return inventory;
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.probiz.estore.inventory.service.InventoryManager#doAllocateStock(com.probiz.estore.common.model.order.SalesOrder, com.probiz.estore.common.model.product.ProductSku, java.lang.Integer)
	 */
	public Integer[] doAllocateStock(SalesOrder salesOrder,ProductSku productSku, Integer quantity)throws OutOfStockException{
		
		Inventory inventory = productSku.getInventory();
		if(inventory.getAvailableQuantity() == null || inventory.getAvailableQuantity() >= quantity){
			//如果是无限库存或者可售库存大于要分配数量
			
			//-----------start:保存库存明细-------------
			InventoryAudit inventoryAudit=new InventoryAudit();
			inventoryAudit.setInventory(inventory);
			inventoryAudit.setProductSku(productSku);
			inventoryAudit.setPreQuantityOnHand(inventory.getQuantityOnHand());
			inventoryAudit.setPostQuantityOnHand(inventory.getQuantityOnHand());
			inventoryAudit.setPreAllocatedQuantity(inventory.getAllocatedQuantity());
			inventoryAudit.setPostAllocatedQuantity(inventory.getAllocatedQuantity()+quantity);
			inventoryAudit.setQuantity(inventoryAudit.getPostAllocatedQuantity()-inventoryAudit.getPreAllocatedQuantity());
			inventoryAudit.setEventType(InventoryConstants.INVENTORY_AUDIT_EVENT_TYPE_STOCK_ALLOCATE);
			inventoryAudit.setSalesOrder(salesOrder);
			inventoryAudit.setEventHandler(getHandler());
			inventoryAuditManager.save(inventoryAudit);
			//-----------end:  保存库存明细-------------
			
			//-----------start:保存库存-------------
			inventory.setAllocatedQuantity(inventory.getAllocatedQuantity()+quantity);
			save(inventory);
			//-----------end:  保存库存-------------
			
			return new Integer[]{quantity,0};
		}else{
			//没有足够的库存直接抛出异常
			throw new OutOfStockException(productSku,inventory.getAvailableQuantity());
		}
	
	}
	
	public Integer[] doAllocateStock4OrderAction(SalesOrder salesOrder,ProductSku productSku, Integer quantity) {
		return doAllocateStock4OrderAction(salesOrder, productSku, quantity, null);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.probiz.estore.inventory.service.InventoryManager#doAllocateStock4OrderAction(com.probiz.estore.common.model.order.SalesOrder, com.probiz.estore.common.model.product.ProductSku, java.lang.Integer)
	 */
	public Integer[] doAllocateStock4OrderAction(SalesOrder salesOrder,ProductSku productSku, Integer quantity, Short eventType){
		Inventory inventory = productSku.getInventory();
			
		//-----------start:保存库存明细-------------
		InventoryAudit inventoryAudit=new InventoryAudit();
		inventoryAudit.setInventory(inventory);
		inventoryAudit.setProductSku(productSku);
		inventoryAudit.setPreQuantityOnHand(inventory.getQuantityOnHand());
		inventoryAudit.setPostQuantityOnHand(inventory.getQuantityOnHand());
		inventoryAudit.setPreAllocatedQuantity(inventory.getAllocatedQuantity());
		inventoryAudit.setPostAllocatedQuantity(inventory.getAllocatedQuantity()+quantity);
		inventoryAudit.setQuantity(inventoryAudit.getPostAllocatedQuantity()-inventoryAudit.getPreAllocatedQuantity());
		inventoryAudit.setEventType(eventType== null ? InventoryConstants.INVENTORY_AUDIT_EVENT_TYPE_STOCK_ALLOCATE_4_ORDER_RETURN : eventType);
		inventoryAudit.setSalesOrder(salesOrder);
		inventoryAudit.setEventHandler(getHandler());
		inventoryAuditManager.save(inventoryAudit);
		//-----------end:  保存库存明细-------------
		
		//-----------start:保存库存-------------
		inventory.setAllocatedQuantity(inventory.getAllocatedQuantity()+quantity);
		save(inventory);
		//-----------end:  保存库存-------------
		
		return new Integer[]{quantity,0};
	}
	
	
	/*
	 * (non-Javadoc)
	 * @see com.probiz.estore.inventory.service.InventoryManager#doCancelAllocateStock(com.probiz.estore.common.model.order.SalesOrder, com.probiz.estore.common.model.product.ProductSku, java.lang.Integer)
	 */
	public void doCancelAllocateStock(SalesOrder salesOrder,ProductSku productSku, Integer quantity) {
		Inventory inventory = productSku.getInventory();
		
		//-----------start:保存库存明细-------------
		InventoryAudit inventoryAudit=new InventoryAudit();
		inventoryAudit.setInventory(inventory);
		inventoryAudit.setProductSku(productSku);
		inventoryAudit.setPreQuantityOnHand(inventory.getQuantityOnHand());
		inventoryAudit.setPostQuantityOnHand(inventory.getQuantityOnHand());
		inventoryAudit.setPreAllocatedQuantity(inventory.getAllocatedQuantity());
		inventoryAudit.setPostAllocatedQuantity(inventory.getAllocatedQuantity()-quantity);
		inventoryAudit.setQuantity(inventoryAudit.getPostAllocatedQuantity()-inventoryAudit.getPreAllocatedQuantity());
		inventoryAudit.setEventType(InventoryConstants.INVENTORY_AUDIT_EVENT_TYPE_STOCK_DEALLOCATE);
		inventoryAudit.setSalesOrder(salesOrder);
		inventoryAudit.setEventHandler(getHandler());
		inventoryAuditManager.save(inventoryAudit);
		//-----------end:  保存库存明细-------------
		
		//-----------start:保存库存-------------
		inventory.setAllocatedQuantity(inventory.getAllocatedQuantity()-quantity);
		save(inventory);
		//-----------end:  保存库存-------------

	}
	
	/*
	 * (non-Javadoc)
	 * @see com.probiz.estore.inventory.service.InventoryManager#doReleaseStock(com.probiz.estore.common.model.order.SalesOrder, com.probiz.estore.common.model.product.ProductSku, java.lang.Integer)
	 */
	public void doReleaseStock(SalesOrder salesOrder,ProductSku productSku, Integer quantity){
		
		Inventory inventory = productSku.getInventory();
		
		//-----------start:保存库存明细-------------
		InventoryAudit inventoryAudit=new InventoryAudit();
		inventoryAudit.setInventory(inventory);
		inventoryAudit.setProductSku(productSku);
		inventoryAudit.setPreQuantityOnHand(inventory.getQuantityOnHand());
		if( inventory.getQuantityOnHand() != null){
			inventoryAudit.setPostQuantityOnHand(inventory.getQuantityOnHand()-quantity);
		}else{
			inventoryAudit.setPostQuantityOnHand(inventory.getQuantityOnHand());
		}
		inventoryAudit.setPreAllocatedQuantity(inventory.getAllocatedQuantity());
		inventoryAudit.setPostAllocatedQuantity(inventory.getAllocatedQuantity()-quantity);
		if(inventoryAudit.getPreQuantityOnHand()!=null && inventoryAudit.getPostQuantityOnHand()!=null){
			inventoryAudit.setQuantity(inventoryAudit.getPostQuantityOnHand()-inventoryAudit.getPreQuantityOnHand());
		}
		inventoryAudit.setEventType(InventoryConstants.INVENTORY_AUDIT_EVENT_TYPE_STOCK_RELEASE);
		inventoryAudit.setSalesOrder(salesOrder);
		inventoryAudit.setEventHandler(getHandler());
		inventoryAuditManager.save(inventoryAudit);
		//-----------end:  保存库存明细-------------
		
		//-----------start:保存库存-------------
		inventory.setAllocatedQuantity(inventory.getAllocatedQuantity()-quantity);
		if( inventory.getQuantityOnHand() != null){
			inventory.setQuantityOnHand(inventory.getQuantityOnHand()-quantity);
		}
		save(inventory);
		//-----------end:  保存库存-------------
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.probiz.estore.inventory.service.InventoryManager#doSaveInventorySetting(com.probiz.estore.common.model.product.ProductSku, com.probiz.estore.common.model.inventory.InventorySettingModel)
	 */
	public Inventory doSaveInventorySetting(ProductSku sku,InventorySettingModel setting){
		Inventory inventory = sku.getInventory();
		inventory.setReorderMinimnm(setting.getReorderMinimnm());
		save(inventory);
		return inventory;
	}
	/*
	 * (non-Javadoc)
	 * @see com.probiz.estore.inventory.service.InventoryManager#searchInventory(com.probiz.estore.common.model.inventory.InventorySearchCriteria, com.probiz.estore.core.search.SearchCriteria)
	 */
	public List<ProductSku> searchInventory(InventorySearchCriteria inventorySearchCriteria ,SearchCriteria searchCriteria){
		return inventoryDao.searchInventory(inventorySearchCriteria, searchCriteria);
	}
	/*
	 * (non-Javadoc)
	 * @see com.probiz.estore.inventory.service.InventoryManager#getLowStockProductSkuLimit(java.lang.Integer)
	 */
	public List<ProductSku> getLowStockProductSkuLimit(Integer maxSize){
		return inventoryDao.getLowStockProductSkuLimit(maxSize);
	}
	/*
	 * (non-Javadoc)
	 * @see com.probiz.estore.inventory.service.InventoryManager#getLackStockProductSkuLimit(java.lang.Integer)
	 */
	public List<ProductSku> getLackStockProductSkuLimit(Integer maxSize){
		return inventoryDao.getLackStockProductSkuLimit(maxSize);
	}
	/*
	 * (non-Javadoc)
	 * @see com.probiz.estore.inventory.service.InventoryManager#sendLowAndLackStockEmails()
	 */
	public void sendLowAndLackStockEmails(){
		Map model = new HashMap();
		List<ProductSku> lackStockProductSkuList = getLackStockProductSkuLimit(50);
		List<ProductSku> lowStockProductSkuList = getLowStockProductSkuLimit(50);
		Long lackStockSize = countLackStockProductSkuTotal();
		Long lowStockSize = countLowStockProductSkuTotal();
		if(lackStockSize.intValue()!=0 || lowStockSize.intValue()!=0){
			model.put("lackStockProductSkuList", lackStockProductSkuList);
			model.put("lowStockProductSkuList", lowStockProductSkuList);
			model.put("lackStockSize", lackStockSize);
			model.put("lowStockSize", lowStockSize);
			msgSendManager.sendMsg(MsgTemplateConstants.MESSAGE_STOCK_MESSAGE, model, new String[]{configUtil.getStockAlertRecipientEmail()}, null, null);
		}	
	}
	/**
	 * 获得处理者
	 * @return
	 */
	private String getHandler(){
		AppUser appUser=(AppUser)RequestContext.getCurrentUser();
		StringBuffer handler;
		if (appUser == null) {
			handler=new StringBuffer("System"); 
		}else if(appUser!=null&&appUser.getUserType().intValue()==AppUser.USER_TYPE_ADMIN.intValue()){
			handler=new StringBuffer("管理员/");
			handler.append(appUser.getAppuserId());
			handler.append("/");
			handler.append(appUser.getFullName());
		}else{
			handler=new StringBuffer("客户/");
			handler.append(appUser.getAppuserId());
			handler.append("/");
			handler.append(appUser.getFullName());
		}
		return handler.toString();
		
	}
	/*
	 * (non-Javadoc)
	 * @see com.probiz.estore.inventory.service.InventoryManager#countLowStockProductSkuTotal()
	 */
	public Long countLowStockProductSkuTotal(){
		return this.inventoryDao.countByFilter(Inventory.FilterHqlName.COUNT_LOW_STOCK);
	}
	/*
	 * (non-Javadoc)
	 * @see com.probiz.estore.inventory.service.InventoryManager#countLackStockProductSkuTotal()
	 */
	public Long countLackStockProductSkuTotal(){
		return this.inventoryDao.countByFilter(Inventory.FilterHqlName.COUNT_LACK_STOCK);
	}
	
	
	
}
